using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

namespace HyxFrame.Core
{

    public class ResourceManager : MonoSingleton<ResourceManager>
    {
        // 缓存已加载的 GameObject 资源
        private readonly Dictionary<string, GameObject> loadedPrefabRes = new();

        // 缓存已加载的配置文件资源（如 JSON 文件）
        private readonly Dictionary<string, TextAsset> loadedConfigRes = new();

        // 缓存已加载的 Sprite 资源
        private readonly Dictionary<string, Sprite> loadedSpriteRes = new();

        protected override void InitManager() { }

        #region 通用加载方法

        /// <summary>
        /// 异步加载资源并缓存。
        /// </summary>
        /// <typeparam name="T">资源类型（如 GameObject、TextAsset、Sprite 等）。</typeparam>
        /// <param name="resourceName">资源名称。</param>
        /// <param name="cache">缓存字典，用于存储已加载的资源。</param>
        /// <returns>返回加载的资源实例。</returns>
        private async Task<T> LoadResourceAsync<T>(string resourceName, Dictionary<string, T> cache) where T : UnityEngine.Object
        {
            // 如果资源已在缓存中，直接返回
            if (cache.TryGetValue(resourceName, out var cachedResource))
            {
                return cachedResource;
            }

            try
            {
                // 使用 Addressables 异步加载资源
                var handle = Addressables.LoadAssetAsync<T>(resourceName);
                var resource = await handle.Task;

                if (resource != null)
                {
                    // 加载成功后将资源存入缓存
                    cache[resourceName] = resource;
                }
                else
                {
                    Debug.LogWarning($"Resource '{resourceName}' loaded but is null.");
                }

                return resource;
            }
            catch (Exception ex)
            {
                // 捕获加载异常并记录错误日志
                Debug.LogError($"Error loading resource '{resourceName}': {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// 同步加载资源并缓存（通过回调返回资源）。
        /// </summary>
        /// <typeparam name="T">资源类型。</typeparam>
        /// <param name="resourceName">资源名称。</param>
        /// <param name="cache">缓存字典。</param>
        /// <param name="action">加载完成后的回调。</param>
        private void LoadResource<T>(string resourceName, Dictionary<string, T> cache, Action<T> action) where T : UnityEngine.Object
        {
            // 如果资源已在缓存中，直接调用回调
            if (cache.TryGetValue(resourceName, out var cachedResource))
            {
                action?.Invoke(cachedResource);
                return;
            }

            // 使用 Addressables 异步加载资源
            var handle = Addressables.LoadAssetAsync<T>(resourceName);
            handle.Completed += operation =>
            {
                if (operation.Status == AsyncOperationStatus.Succeeded)
                {
                    var resource = operation.Result;
                    if (resource != null)
                    {
                        // 加载成功后将资源存入缓存并调用回调
                        cache[resourceName] = resource;
                        action?.Invoke(resource);
                    }
                    else
                    {
                        Debug.LogWarning($"Resource '{resourceName}' loaded but is null.");
                    }
                }
                else
                {
                    // 加载失败时记录错误日志
                    Debug.LogError($"Failed to load resource '{resourceName}' from Addressables.");
                }
            };
        }

        #endregion

        #region 配置文件加载

        /// <summary>
        /// 异步读取 JSON 数据。
        /// </summary>
        /// <param name="resourceName">JSON 文件名称。</param>
        /// <returns>返回 JSON 文件的文本内容。</returns>
        public async Task<string> ReadJsonData(string resourceName)
        {
            var textAsset = await LoadResourceAsync(resourceName, loadedConfigRes);
            return textAsset?.text;
        }

        /// <summary>
        /// 同步加载配置文件资源。
        /// </summary>
        /// <param name="resourceName">配置文件名称。</param>
        /// <param name="action">加载完成后的回调。</param>
        public void LoadConfigResource(string resourceName, Action<TextAsset> action)
        {
            LoadResource(resourceName, loadedConfigRes, action);
        }

        #endregion

        #region GameObject 加载

        /// <summary>
        /// 异步加载 GameObject 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        /// <returns>返回加载的 GameObject 实例。</returns>
        public async Task<GameObject> LoadGameObjectResAsync(string resourceName)
        {
            return await LoadResourceAsync(resourceName, loadedPrefabRes);
        }

        /// <summary>
        /// 同步加载 GameObject 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        /// <param name="action">加载完成后的回调。</param>
        public void LoadGameObjectRes(string resourceName, Action<GameObject> action = null)
        {
            LoadResource(resourceName, loadedPrefabRes, action);
        }

        #endregion

        #region 图片加载

        /// <summary>
        /// 异步加载 Sprite 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        /// <returns>返回加载的 Sprite 实例。</returns>
        public async Task<Sprite> LoadSpriteAsync(string resourceName)
        {
            return await LoadResourceAsync(resourceName, loadedSpriteRes);
        }

        /// <summary>
        /// 同步加载 Sprite 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        /// <param name="action">加载完成后的回调。</param>
        public void LoadSprite(string resourceName, Action<Sprite> action = null)
        {
            LoadResource(resourceName, loadedSpriteRes, action);
        }

        #endregion

        #region 资源释放

        /// <summary>
        /// 释放指定资源。
        /// </summary>
        /// <typeparam name="T">资源类型。</typeparam>
        /// <param name="resourceName">资源名称。</param>
        /// <param name="cache">缓存字典。</param>
        private void ReleaseResource<T>(string resourceName, Dictionary<string, T> cache) where T : UnityEngine.Object
        {
            if (cache.Remove(resourceName, out var resource))
            {
                Addressables.Release(resource);
            }
            else
            {
                Debug.LogWarning($"Attempted to release resource '{resourceName}' but it was not found in cache.");
            }
        }

        /// <summary>
        /// 释放配置文件资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        public void ReleaseConfig(string resourceName)
        {
            ReleaseResource(resourceName, loadedConfigRes);
        }

        /// <summary>
        /// 释放 GameObject 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        public void ReleaseGameObject(string resourceName)
        {
            ReleaseResource(resourceName, loadedPrefabRes);
        }

        /// <summary>
        /// 释放 Sprite 资源。
        /// </summary>
        /// <param name="resourceName">资源名称。</param>
        public void ReleaseSprite(string resourceName)
        {
            ReleaseResource(resourceName, loadedSpriteRes);
        }

        #endregion

        /// <summary>
        /// 在销毁时释放所有资源。
        /// </summary>
        protected override void OnDestroy()
        {
            ReleaseAllResources(loadedConfigRes, "Config");
            ReleaseAllResources(loadedPrefabRes, "GameObject");
            ReleaseAllResources(loadedSpriteRes, "Sprite");
        }

        /// <summary>
        /// 释放所有缓存的资源。
        /// </summary>
        /// <typeparam name="T">资源类型。</typeparam>
        /// <param name="cache">缓存字典。</param>
        /// <param name="resourceType">资源类型名称（用于日志）。</param>
        private void ReleaseAllResources<T>(Dictionary<string, T> cache, string resourceType) where T : UnityEngine.Object
        {
            foreach (var resourceName in cache.Keys)
            {
                Addressables.Release(cache[resourceName]);
            }
            Debug.Log($"{resourceType} resources released: {cache.Count}");
            cache.Clear();
        }
    }



}